/**
 * @file spi_dev.h
 * @author LokLiang (lokliang@163.com)
 * @brief 定义 SPI 上的设备的硬件接口
 * @version 0.1
 * @date 2023-06-07
 *
 * @copyright Copyright (c) 2023
 *
 */

#ifndef __SPI_DEV_H__
#define __SPI_DEV_H__

/* Includes ------------------------------------------------------------------*/

#include "sys_init.h"

#ifdef __cplusplus
extern "C" {
#endif /* #ifdef __cplusplus */

/* Macros --------------------------------------------------------------------*/

/* Typedef -------------------------------------------------------------------*/

typedef const struct spi_dev *spi_dev_t;

typedef void (*spi_dev_irq_cb)(spi_dev_t spi_dev_hdl, void *arg);

/* Function prototypes -------------------------------------------------------*/

__static_inline spi_dev_t spi_dev_binding(const char *device_name);
__static_inline const char *spi_dev_search(const char *prefix_name, unsigned int num);

__static_inline int spi_dev_init(spi_dev_t spi_dev_hdl, const void *param);
__static_inline int spi_dev_deinit(spi_dev_t spi_dev_hdl);

__static_inline int spi_dev_lock(spi_dev_t spi_dev_hdl);
__static_inline void spi_dev_unlock(spi_dev_t spi_dev_hdl);

__static_inline void spi_dev_call_enable(spi_dev_t spi_dev_hdl, spi_dev_irq_cb irq, void *arg);
__static_inline void spi_dev_call_disable(spi_dev_t spi_dev_hdl);

__static_inline int spi_dev_cs_set(spi_dev_t spi_dev_hdl);
__static_inline int spi_dev_cs_reset(spi_dev_t spi_dev_hdl);

__static_inline int spi_dev_write(spi_dev_t spi_dev_hdl, const void *src, uint32_t size);
__static_inline int spi_dev_read(spi_dev_t spi_dev_hdl, void *dst, uint32_t size);

__static_inline int spi_dev_is_busy(spi_dev_t spi_dev_hdl);

/* Code ----------------------------------------------------------------------*/

typedef struct
{
    int (*init)(spi_dev_t spi_dev_hdl, const void *param);
    int (*deinit)(spi_dev_t spi_dev_hdl);
    int (*lock)(spi_dev_t spi_dev_hdl);
    void (*unlcok)(spi_dev_t spi_dev_hdl);
    void (*call_enable)(spi_dev_t spi_dev_hdl, spi_dev_irq_cb cb, void *arg);
    void (*call_disable)(spi_dev_t spi_dev_hdl);
    int (*cs_set)(spi_dev_t spi_dev_hdl);
    int (*cs_reset)(spi_dev_t spi_dev_hdl);
    int (*write)(spi_dev_t spi_dev_hdl, const void *src, uint32_t size);
    int (*read)(spi_dev_t spi_dev_hdl, void *dst, uint32_t size);
    int (*is_busy)(spi_dev_t spi_dev_hdl);
} spi_dev_api_t;

typedef struct
{
    void *param; // 自定义配置参数
} spi_dev_cfg_t;

struct spi_dev
{
    spi_dev_api_t api;
    spi_dev_cfg_t *cfg;
};

/**
 * @brief 绑定一个名为 device_name 的 spi_dev 存储设备模块。
 * 模块的对象数据由 @c OBJ_EXPORT_DEVICE 所定义。
 *
 * @param device_name 模块名称
 * @return spi_dev_t 设备对象，在应用前需要使用 spi_dev_init() 进行初始化
 */
__static_inline spi_dev_t spi_dev_binding(const char *device_name)
{
    return (spi_dev_t)device_binding(device_name);
}

/**
 * @brief 查找 spi_dev_binding() 可用的模块对象名。
 *
 * @param prefix_name 模块对象名前缀。如 "SPI:"
 * @param num 匹配到 prefix_name 的第几次时返回，范围 0..n
 * @return const char * 匹配到的第 num 个名称为 prefix_name.* 的完整对象名
 * @return NULL 表示没对象
 */
__static_inline const char *spi_dev_search(const char *prefix_name, unsigned int num)
{
    return device_search(prefix_name, num);
}

/**
 * @brief 执行初始化。在使用任何 API 前都需要先初始化。
 * 注意其中可能存在动态申请的内存，使用 spi_dev_deinit() 释放其内存
 *
 * @param spi_dev_hdl 来自 spi_dev_binding() 取得的对象
 * @param param 自定义配置参数
 * @return int 0 表示操作成功；
 * @return int -1 表示对象无效或操作失败
 */
__static_inline int spi_dev_init(spi_dev_t spi_dev_hdl, const void *param)
{
    if (spi_dev_hdl)
        return spi_dev_hdl->api.init(spi_dev_hdl, param);
    return -1;
}

/**
 * @brief 取消初始化
 *
 * @param spi_dev_hdl 已被 spi_dev_init() 初始化的的对象
 * @return int 0 表示操作成功；
 * @return int 1 表示设备忙；
 * @return int -1 表示对象无效或操作失败
 */
__static_inline int spi_dev_deinit(spi_dev_t spi_dev_hdl)
{
    if (spi_dev_hdl)
        return spi_dev_hdl->api.deinit(spi_dev_hdl);
    return -1;
}

/**
 * @brief 锁定总线
 *
 * @param spi_dev_hdl 已被 spi_dev_init() 初始化的的对象
 * @return int 0 表示操作成功；
 * @return int 1 表示设备忙；
 * @return int -1 表示对象无效或操作失败
 */
__static_inline int spi_dev_lock(spi_dev_t spi_dev_hdl)
{
    if (spi_dev_hdl)
        return spi_dev_hdl->api.lock(spi_dev_hdl);
    return -1;
}

/**
 * @brief 解锁总线
 *
 * @param spi_dev_hdl 已被 spi_dev_init() 初始化的的对象
 */
__static_inline void spi_dev_unlock(spi_dev_t spi_dev_hdl)
{
    if (spi_dev_hdl)
        spi_dev_hdl->api.unlcok(spi_dev_hdl);
}

/**
 * @brief 开启数据传输完成中断，并设置回调函数。
 * 当使用 spi_dev_write() 或 spi_dev_read() 所设置的读写操作完成后，将执行指定回调函数
 *
 * @param spi_dev_hdl 已被 spi_dev_init() 初始化的的对象
 * @param irq 指定回调函数
 * @param arg 回调函数附带的参数
 */
__static_inline void spi_dev_call_enable(spi_dev_t spi_dev_hdl, spi_dev_irq_cb irq, void *arg)
{
    if (spi_dev_hdl)
        spi_dev_hdl->api.call_enable(spi_dev_hdl, irq, arg);
}

/**
 * @brief 关闭数据传输完成中断
 *
 * @param spi_dev_hdl 已被 spi_dev_init() 初始化的的对象
 */
__static_inline void spi_dev_call_disable(spi_dev_t spi_dev_hdl)
{
    if (spi_dev_hdl)
        spi_dev_hdl->api.call_disable(spi_dev_hdl);
}

/**
 * @brief 使对应的设备的 CS 引脚输出高电平
 *
 * @param spi_dev_hdl 已被 spi_dev_init() 初始化的的对象
 * @return int 0 表示操作成功；
 * @return int 1 表示设备忙；
 * @return int -1 表示对象无效或操作失败
 */
__static_inline int spi_dev_cs_set(spi_dev_t spi_dev_hdl)
{
    if (spi_dev_hdl)
        return spi_dev_hdl->api.cs_set(spi_dev_hdl);
    return -1;
}

/**
 * @brief  * @brief 使对应的设备的 CS 引脚输出低电平
 *
 * @param spi_dev_hdl 已被 spi_dev_init() 初始化的的对象
 * @return int 0 表示操作成功；
 * @return int 1 表示设备忙；
 * @return int -1 表示对象无效或操作失败
 */
__static_inline int spi_dev_cs_reset(spi_dev_t spi_dev_hdl)
{
    if (spi_dev_hdl)
        return spi_dev_hdl->api.cs_reset(spi_dev_hdl);
    return -1;
}

/**
 * @brief 操作 SPI 写数据到总线上
 *
 * @param spi_dev_hdl 已被 spi_dev_init() 初始化的的对象
 * @param src 来源数据
 * @param size 数据长度（字节）
 * @return int 0 表示操作成功；
 * @return int 1 表示设备忙；
 * @return int -1 表示对象无效或操作失败
 */
__static_inline int spi_dev_write(spi_dev_t spi_dev_hdl, const void *src, uint32_t size)
{
    if (spi_dev_hdl)
        return spi_dev_hdl->api.write(spi_dev_hdl, src, size);
    return -1;
}

/**
 * @brief 操作 SPI 从总线上读数据
 *
 * @param spi_dev_hdl 已被 spi_dev_init() 初始化的的对象
 * @param dst 用于保存数据的内存
 * @param size 数据长度（字节）
 * @return int 0 表示操作成功；
 * @return int 1 表示设备忙；
 * @return int -1 表示对象无效或操作失败
 */
__static_inline int spi_dev_read(spi_dev_t spi_dev_hdl, void *dst, uint32_t size)
{
    if (spi_dev_hdl)
        return spi_dev_hdl->api.read(spi_dev_hdl, dst, size);
    return -1;
}

/**
 * @brief 查询忙状态
 *
 * @param spi_dev_hdl 已被 spi_dev_init() 初始化的的对象
 * @return int 0 表示空闲；
 * @return int 1 表示设备忙；
 * @return int -1 表示对象无效或操作失败；
 */
__static_inline int spi_dev_is_busy(spi_dev_t spi_dev_hdl)
{
    if (spi_dev_hdl)
        return spi_dev_hdl->api.is_busy(spi_dev_hdl);
    return -1;
}

#ifdef __cplusplus
} /* extern "C" */
#endif /* #ifdef __cplusplus */

#endif
